#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <curses.h>
#include "network.h"
#include "common.h"

#define BUF_SIZE 1024

WINDOW * title_remote;
WINDOW * title_local;
WINDOW * remote;
WINDOW * local;
WINDOW * screen;
bool screen_initialized = 0;

void init_screen()
{
  int w, h;
  screen = initscr();
  screen_initialized = 1;
  getmaxyx(screen, h, w);
  
  title_remote = newwin(1, w, 0, 0);
  remote = newwin(h/2-1, w, 1, 0);
  title_local = newwin(1, w, h/2, 0);
  local = newwin(h/2-1, w, h/2+1, 0); 
  wclear(title_local);
  wclear(title_remote);
  wclear(local);
  wclear(remote);
  wprintw(title_local, "LOCAL:");
  wprintw(title_remote, "REMOTE:");
  wrefresh(title_local);
  wrefresh(title_remote);
  wrefresh(local);
  wrefresh(remote);
} 

void wprint_buf(WINDOW * window, char * buf, int size)
{
  int i;
  for (i = 0; i< size; i++) {
    if (waddch(window, buf[i] == 13 ? '\n' : buf[i]) == ERR) {
      wclear(window);
      waddch(window, buf[i] == 13 ? '\n' : buf[i]);
    }    
  }
  wrefresh(window);
}


void end_screen() 
{
  delwin(title_remote);
  delwin(remote);
  delwin(title_local);
  delwin(local);
  screen_initialized = 0;
  endwin();
}

int stop_server = 0;

int socket_id = -1;

int server_socket_id = -1;

int talk()
{
  char buf[BUF_SIZE];
  fd_set desciptors_set; 
  FD_ZERO(&desciptors_set);
  FD_SET(socket_id, &desciptors_set);
  FD_SET(STDIN_FILENO, &desciptors_set);

  int result = select(max(STDIN_FILENO, socket_id)+1, &desciptors_set, 0, 0, 0);
  if (result < 0) {
    return 0;
  }

  if (FD_ISSET(socket_id, &desciptors_set)) {    
    int result = read(socket_id, buf, BUF_SIZE);
    error_if(result == -1, "Unanable to read");
    if (result) {
      wprint_buf(remote, buf, result);
    } else  {
      return 0;
    }
  }
  if (FD_ISSET(STDIN_FILENO, &desciptors_set)) {
    int size = read(STDIN_FILENO, buf, BUF_SIZE);
    error_if(size == -1, "Unanable to read");
    wprint_buf(local, buf, size);
    int result = write(socket_id, buf, size);
    error_if(result < 0, "Error in writing");
  }
  return 1;
}


void sigint_server(int no)
{
  if (screen_initialized)
    end_screen();
  exit(0);
}


void sigint_client(int no)
{
  end_screen();
  exit(0);
}


void start_server()
{
  printf("Waiting for connection...\n");
  struct sockaddr_in client_adress;
  error_if(signal(SIGINT, &sigint_server) == SIG_ERR, "Unanable to set signal");
  server_socket_id = server_socket_open(PORT);
  while (1) {
    socket_id = server_socket_accept(server_socket_id, &client_adress);
    init_screen(); 
    while (talk()) {
    }

    error_if(close(socket_id) == -1, "Unanable to close");
    end_screen();
  }
  error_if(close(server_socket_id) == -1, "Unanable to close");
}

void start_client(char * host)
{
  printf("Connecting");  
  socket_id = socket_open(host);
  signal(SIGINT, &sigint_client);
  init_screen();  
  while (talk(socket_id)) {
  }
  error_if(close(socket_id) == -1, "Unanable to close");
  end_screen();
}

int main (int argi, char * argv[]) 
{
  if (argi == 1) {
      start_server();
  }
  else if (argi == 2) {
    start_client(argv[1]);
  } else {
    printf("Usage:\n\ttalk - for server\n\talk [host] - for client\n");
  }
  return 0;
}

